package com.rogerfan.easy.shiro;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.annotation.PostConstruct;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.rogerfan.easy.model.hy.PurviewDto;
import com.rogerfan.easy.model.hy.RoleDto;
import com.rogerfan.easy.model.hy.UserDto;
import com.rogerfan.easy.model.hy.UserDtoExample;
import com.rogerfan.easy.service.hy.PurviewService;
import com.rogerfan.easy.service.hy.RoleService;
import com.rogerfan.easy.service.hy.UserService;

public class ShiroDbRealm extends AuthorizingRealm {
	private static final Logger log = LoggerFactory
			.getLogger(ShiroDbRealm.class);

	@Autowired
	private UserService userServices;
	@Autowired
	private RoleService roleServices;
	@Autowired
	private PurviewService purviewServices;
	@Autowired
	private ShiroRedisCacheManager cacheManage;

	

	/**
	 * 认证回调函数, 登录时调用.
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken authcToken) throws AuthenticationException {
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
		log.debug("账号：{}请求登录验证，来源IP:{}", token.getUsername(), token.getHost());

		UserDtoExample _ue = new UserDtoExample();
		_ue.createCriteria().andMobileEqualTo(token.getUsername());
		UserDto userInfo = userServices.selectOneByExample(_ue);
		if (userInfo == null){
			 throw new UnknownAccountException();  
		}
		String principal = userInfo.getId() + "~~" + userInfo.getMobile();
		clearCachedAuthorizationInfo(principal);

		return new SimpleAuthenticationInfo(userInfo.getId() + "~~"
				+ userInfo.getMobile(), userInfo.getPassword(), getName());

	}

	/**
	 * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(
			PrincipalCollection principals) {

		@SuppressWarnings("unchecked")
		Collection<String> realms = principals.fromRealm(getName());
		String principal = realms.iterator().next();

		UserDto auth = ShiroUtils.getUserFormPrincipal(principal);
		log.debug("{}用户进行授权", auth.getMobile());
		List<String> roleList = new ArrayList<String>();
		List<String> permissionList = new ArrayList<String>();

		List<RoleDto> _roleList = roleServices.selectByUserId(auth.getId());
		// 获取用户角色权限
		if (_roleList != null && _roleList.size() > 0) {
			for (RoleDto role : _roleList) {
				roleList.add(String.valueOf(role.getId()));
			}
		}
		List<PurviewDto> _purviewList = purviewServices.selectByUserId(auth
				.getId());
		if (_purviewList != null)
			for (PurviewDto purview : _purviewList) {
				permissionList.add(purview.getPurCode());
			}
		// 为当前用户设置角色和权限
		SimpleAuthorizationInfo simpleAuthorInfo = new SimpleAuthorizationInfo();
		simpleAuthorInfo.addRoles(roleList);
		simpleAuthorInfo.addStringPermissions(permissionList);
		return simpleAuthorInfo;
	}



	/**
	 * 更新用户授权信息缓存.
	 */
	public void clearCachedAuthorizationInfo(String principal) {
		SimplePrincipalCollection principals = new SimplePrincipalCollection(
				principal, getName());
		clearCachedAuthorizationInfo(principals);
	}

	/**
	 * 清除所有用户授权信息缓存.
	 */
	public void clearAllCachedAuthorizationInfo() {
		Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
		if (cache != null) {
			for (Object key : cache.keys()) {
				cache.remove(key);
			}
		}
	}

}
